package org.sourcecode.common.secure;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import javax.imageio.ImageIO;


public class Captcha {

	//
	private int width = 160;

	private int height = 40;

	private int codeCount = 5;

	private int lineCount = 150;

	private String code = null;

	private BufferedImage buffImg = null;

	// private char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
	// 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
	// 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7',
	// '8', '9' };

	final String[] codeSequence = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f",
			"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" };

	public Captcha() {
		this.createCode();
	}

	/**
	 * 
	 * @param width
	 * @param height
	 */
	public Captcha(int width,int height) {
		this.width = width;
		this.height = height;
		this.createCode();
	}

	/**
	 * 
	 * @param width
	 * @param height
	 * @param codeCount
	 * @param lineCount
	 */
	public Captcha(int width,int height,int codeCount,int lineCount) {
		this.width = width;
		this.height = height;
		this.codeCount = codeCount;
		this.lineCount = lineCount;
		this.createCode();
	}

	public void createCode(){
		int x = 0,fontHeight = 0,codeY = 0;
		int red = 0,green = 0,blue = 0;

		x = width / ( codeCount + 2 );//
		fontHeight = height - 2;//
		codeY = height - 4;

		//
		buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics2D g = buffImg.createGraphics();
		//
		Random random = new Random();
		//
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, width, height);
		//
		ImgFontByte imgFont = new ImgFontByte();
		Font font = imgFont.getFont(fontHeight);
		g.setFont(font);

		for (int i = 0;i < lineCount;i++ ) {
			int xs = random.nextInt(width);
			int ys = random.nextInt(height);
			int xe = xs + random.nextInt(width / 8);
			int ye = ys + random.nextInt(height / 8);
			red = random.nextInt(255);
			green = random.nextInt(255);
			blue = random.nextInt(255);
			g.setColor(new Color(red, green, blue));
			g.drawLine(xs, ys, xe, ye);
		}

		// randomCode
		StringBuffer randomCode = new StringBuffer();
		//
		for (int i = 0;i < codeCount;i++ ) {
			String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
			//
			red = random.nextInt(255);
			green = random.nextInt(255);
			blue = random.nextInt(255);
			g.setColor(new Color(red, green, blue));
			g.drawString(strRand, ( i + 1 ) * x, codeY);
			//
			randomCode.append(strRand);
		}
		//
		code = randomCode.toString();
	}

	public void write(String path) throws IOException{
		OutputStream sos = new FileOutputStream(path);
		this.write(sos);
	}

	public void write(OutputStream sos) throws IOException{
		ImageIO.write(buffImg, "png", sos);
	}

	public BufferedImage getBuffImg(){
		return buffImg;
	}

	public String getCode(){
		return code;
	}

	class ImgFontByte {

		public Font getFont(int fontHeight){
			try {
				Font baseFont = Font.createFont(Font.TRUETYPE_FONT, new ByteArrayInputStream(hex2byte(getFontByteStr())));
				return baseFont.deriveFont(Font.PLAIN, fontHeight);
			} catch (Exception e) {
				return new Font("Arial", Font.PLAIN, fontHeight);
			}
		}

		private byte[] hex2byte(String str){
			if (str == null)
				return null;
			str = str.trim();
			int len = str.length();
			if (len == 0 || len % 2 == 1)
				return null;

			byte[] b = new byte[len / 2];
			try {
				for (int i = 0;i < str.length();i += 2 ) {
					b[i / 2] = (byte) Integer.decode("0x" + str.substring(i, i + 2)).intValue();
				}
				return b;
			} catch (Exception e) {
				return null;
			}
		}

		/**
		 * ttf
		 * 
		 * @return
		 */
		private String getFontByteStr(){
			return null;
		}
	}
}
